<template>
  <div class="lg-table" ref="mytbref">
  <div class="search-form" :style="{ maxHeight: searchShow ?'300px':'0px'}">
    <a-form
      width="100%"
      v-if="searchColumns.length && searchShow"
      ref="formRef"
      name="advanced_search"
      :class="
        !expand ? 'ant-advanced-search-form-expand' : 'ant-advanced-search-form'
      "
      :model="searchParam"
      @finish="onSearch"
    >
      <a-row :gutter="24" style="margin: 0">
        <template v-for="(item, i) in searchColumns" :key="i">
          <a-col
            v-show="expand || i <= 2"
            :span="6"
            v-if="!hiddenRule[item.dataIndex] || hiddenRule[item.dataIndex](searchParam)"
          >
            <a-form-item :name="item.dataIndex">
              <template #label>
                <slot name="title" v-bind="item" v-if="hasSlot('title')"></slot>
                <span v-else>{{ item.title }} </span>
              </template>
              <!-- 文本框 -->
              <template
                v-if="item.searchType == undefined || item.searchType == 'text'"
              >
                <a-input
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                  :placeholder="t('config.required') + item.title "
                  allow-clear
                />
              </template>

              <!-- 数字输入框 -->
              <template v-if="item.searchType == 'number'">
                <a-input-number
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                  :placeholder="t('config.required') + item.title "
                  allow-clear
                />
              </template>

              <!-- 下拉筛选 -->
              <template v-if="item.searchType == 'select'">
                <a-select
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                  :placeholder="t('config.select') + item.title "
                  allow-clear
                >
                  <a-select-option
                    v-for="itemValue in item.enum"
                    :key="itemValue.value"
                    :value="itemValue.value"
                    :disabled="itemValue.disabled"
                    > 
                    {{ itemValue.locale? itemValue.locale[locale]:itemValue.label }}
                    </a-select-option
                  >
                </a-select>
              </template>

              <!-- 开关 -->
              <template v-if="item.searchType == 'switch'">
                <a-switch
                  v-model:checked="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                />
              </template>

              <!-- 滑动输入条 -->
              <template v-if="item.searchType == 'slider'">
                <a-slider
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                />
              </template>

              <!-- 单选 -->
              <template v-if="item.searchType == 'radio'">
                <a-radio-group
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                >
                  <a-radio
                    v-for="itemValue in item.enum"
                    :key="itemValue.value"
                    :disabled="itemValue.disabled"
                    :value="itemValue.value"
                  >
                     {{ itemValue.locale? itemValue.locale[locale]:itemValue.label }}
                  </a-radio>
                </a-radio-group>
              </template>

              <!-- 多选 -->
              <template v-if="item.searchType == 'checkbox'">
                <a-checkbox-group
                  style="width: 100%"
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                >
                  <a-row>
                    <a-col
                      :span="item?.searchProps?.span || 8"
                      v-for="itemValue in item.enum"
                      :key="itemValue.value"
                    >
                      <a-checkbox
                        :value="itemValue.value"
                        :disabled="itemValue.disabled"
                        style="line-height: 32px"
                      >
                         {{ itemValue.locale? itemValue.locale[locale]:itemValue.label }}
                      </a-checkbox>
                    </a-col>
                  </a-row>
                </a-checkbox-group>
              </template>

              <!-- 评分 -->
              <template v-if="item.searchType == 'rate'">
                <a-rate
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                  allow-half
                />
              </template>

              <!-- 日期选择器 -->
              <template v-if="item.searchType == 'date'">
                <a-date-picker
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                  valueFormat="YYYY-MM-DD"
                >
                </a-date-picker>
              </template>

              <!-- 日期选择器时间段 -->
              <template v-if="item.searchType == 'rangeDate'">
                <a-range-picker
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                  valueFormat="YYYY-MM-DD"
                >
                </a-range-picker>
              </template>

              <!-- 时间选择器 -->
              <template v-if="item.searchType == 'time'">
                <a-time-picker
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                />
              </template>

              <!-- 树形选择 -->
              <template v-if="item.searchType == 'treeSelect'">
                <a-tree-select
                  v-model:value="searchParam[item.dataIndex]"
                  style="width: 100%"
                  v-bind="item.searchProps"
                  :tree-data="item.enum"
                  allow-clear
                  :show-checked-strategy="SHOW_PARENT"
                  :placeholder="t('config.select') + item.title "
                  :field-names="FiledName"
                />
              </template>

              <!-- 多行文本域 -->
              <template v-if="item.searchType == 'textarea'">
                <a-textarea
                  v-model:value="searchParam[item.dataIndex]"
                  v-bind="item.searchProps"
                  :placeholder="t('config.select') + item.title "
                  :auto-size="{ minRows: 2, maxRows: 5 }"
                />
              </template>
            </a-form-item>
          </a-col>
        </template>
        <a-col :span="6" style="text-align: left">
          <a-button type="primary" html-type="submit">{{
            t('config.search')
          }}</a-button>
          <a-button style="margin: 0 8px" @click="onLoadFn">{{
             t('config.reset')
          }}</a-button>

          <a style="font-size: 12px" v-if="searchColumns.length > 3" @click="expand = !expand">
            <template v-if="expand">
              <UpOutlined /> {{t('config.packup')}} 
            </template>
            <template v-else>
              <DownOutlined /> {{t('config.develop')}} 
            </template>
            
          </a>
        </a-col>
      </a-row>
    </a-form>
  </div>
    <!-- :scroll="{ x: 1500, y: 300 }" -->
    <div class="w-full bg-white p-6">
      <div class="pb-6 flex justify-between">
        <a-space size="middle">
          <a-button type="primary" @click="add" v-if="shouldEdit">
            <template #icon>
              <plus-outlined />
            </template>
            {{ t('config.add') }} 
          </a-button>
          <div v-else></div>
        </a-space>

        <a-space size="middle">
          <a-tooltip
            class="text-lg"
            v-if="searchColumns.length"
            placement="topLeft"
            @click="toogleSearchShow"
          >
            <template #title>
              <!-- 筛选 -->
              <span> {{  t('config.screen') }}</span>
            </template>
            <SearchOutlined />
          </a-tooltip>

           <!-- 刷新 -->
          <a-tooltip class="text-lg" placement="topLeft" @click="refresh">
            <template #title>
              <span> {{  t('config.refresh') }}</span>
            </template>
            <redo-outlined />
          </a-tooltip>

          <a-dropdown placement="bottom" trigger="['click']">
            <a-tooltip class="text-lg" placement="topLeft">
              <template #title>
                <!-- 密度 -->
                <span> {{   t('config.density')}}</span>
              </template>
              <column-height-outlined />
            </a-tooltip>
            <template #overlay>
              <a-menu :selectedKeys="[tableSize]" @click="setTableSize">
                <a-menu-item key="default">
                  <a href="javascript:;"> {{ t('config.large') }}</a>
                </a-menu-item>
                <a-menu-item key="middle">
                  <a href="javascript:;">{{ t('config.default') }}</a>
                </a-menu-item>
                <a-menu-item key="small">
                  <a href="javascript:;">{{ t('config.small') }}</a>
                </a-menu-item>
              </a-menu>
            </template>
          </a-dropdown>
          <!-- 拖拽 -->
          <a-tooltip
            class="text-lg"
            placement="topLeft"
            v-if="isShowDraggle"
            @click="() => setShouldSort(!shouldSort)"
          >
            <template #title>
              <span> {{ t('config.drag')  }} </span>
            </template>
            <unordered-list-outlined />
          </a-tooltip>
        </a-space>
      </div>
      <!--  || -->
      <a-table
        id="mytb"
        :scroll="{ x:  mytbref?.clientWidth - 30 }"
        :columns="tableColumns"
        rowKey="id"
        :pagination="tablePagination"
        :childrenColumnName="childrenName"
        :bordered="border"
        :data-source="tableList"
        v-bind="tableOtherProps"
        :loading="loading"
        @change="change"
        :row-selection="useSelection ? rowSelection : null"
        :size="tableSize"
        @resizeColumn="handleResizeColumn"
      >
        <template #headerCell="{ column }" v-if="hasSlot('title')">
          <slot name="title" v-bind="{ ...column }"></slot>
        </template>

        <template #bodyCell="{ record, index, column }">
          <dic-tag v-if="showTag(column)" :type="column.dic" :value="record[column.dataIndex]"></dic-tag>
          <unordered-list-outlined
            class="anticon-align-left"
            v-else-if="column.dataIndex === '__sort__'"
          />
          <span v-else-if="!record[column.dataIndex] && record[column.dataIndex] !== 0"> - </span>
          <slot
            v-else
            name="bodyCell"
            v-bind="{ record, index, column }"
          ></slot>
        </template>
      </a-table>
    </div>
  </div>
</template>
<script lang="ts">
import {
  defineComponent,
  ComponentPublicInstance,
  ExtractPropTypes,
  PropType,
  computed,
  ref,
  watch,
  onMounted,
} from 'vue';
import {
  FormInstance,
  TreeSelect,
  PaginationProps,
} from 'ant-design-vue';

import {
  UnorderedListOutlined,
  ColumnHeightOutlined,
  RedoOutlined,
  SearchOutlined,
  UpOutlined,
  DownOutlined
} from '@ant-design/icons-vue';
import DicTag from "@/components/DicTag/index.vue"
import { PlusOutlined } from '@ant-design/icons-vue';
import './style/index.less';
import useTable from './useTable';
import type {
  ColumnsType,
  mergeRow,
  TableSortProps,
  TableStateProps,
  TableSource,
} from './types';
import useMerge from './useMerge';
import useSelect from './useSelect';
import useSort from './useSort';
import { useI18n } from 'vue-i18n'
import { isEmpty } from 'lodash'

export type TableExpose = {
  changeSelectedRowKeys: (selectedRowKeys?: string[]) => void;
  changeSortIndex: (sortIndex: TableSortProps['sortIndex']) => void;
  onload: (totalParam: TableStateProps['totalParam']) => void;
  refresh: (resetPage?: string[]) =>void;
  add: () => void;
};

export const tableProps = () => ({
  columns: { type: Array as PropType<ColumnsType[]>, required: true },
  pagination: { type: Boolean, default: true },
  initParam: { type: Object, default: {} },
  hiddenRule: {
    type: Object as PropType<Record<string, (params: any) => boolean>>,
    default: Object,
  }, //表单项隐藏某项
  border: { type: Boolean, default: false },
  toolButton: { type: Boolean, default: true },
  childrenName: { type: String, default: 'children' },
  useSelection: { type: Boolean, default: false },
  tableSource: {
    type: Object as PropType<TableSource>,
    default: () => ({ current: 1, pageSize: 20, total: 0, list: [] }),
  },
  shouldEdit: { type: Boolean, default: true },
  draggle: { type: Boolean, default: false },
  merge: { type: Array as PropType<string[]>, default: [] },
  mergeRow: { type: Array as PropType<mergeRow>, default: [] },
});

export type TableProps = Partial<
  ExtractPropTypes<ReturnType<typeof tableProps>>
>;

export type TableInstance = ComponentPublicInstance<TableProps, TableExpose>;

const LgTable = defineComponent({
  name: 'pro-table',
  useTable,
  components: {
    UnorderedListOutlined,
    ColumnHeightOutlined,
    RedoOutlined,
    SearchOutlined,
    PlusOutlined,
    UpOutlined,
    DownOutlined,
    DicTag
  },
  props: tableProps(),
  setup(props, { emit, expose, slots }) {
    const { t,locale } = useI18n({inheritLocale: true,useScope: 'local'})

    const expand = ref(true);
    const formRef = ref<FormInstance>();
    const mytbref = ref();
    const FiledName = ref({
      children: 'children',
      label: 'label',
      value: 'value',
    });
    const { SHOW_PARENT } = TreeSelect;

    // 表格操作 Hooks
    const {
      searchShow,
      tableData,
      pageable,
      searchParam,
      searchInitParam,
      loading,
      tableSize,
      totalParam,
      search,
      reset,
      changeTable,
      setTableSize,
      updateTableData,
      onLoad,
      toogleSearchShow,
      setValueByKey,
      getsearchParam,
    } = useTable(
      props.initParam,
      props.pagination,
      locale
    );

    // 表格选择操作
    const { selectedRowKeys, onSelectChange, rowSelection } = useSelect();
    // 表格拖拽hooks
    const { sortIndex, shouldSort, initSortable, setShouldSort } = useSort();

    const { listAppendFn } = useMerge();

    // 判断表格行单元格是否需要展示tag
    const showTag = (column:ColumnsType)=> {
      return !(!column.dic || isEmpty(column.enum))
    }

    // 表格额外属性
    const tableOtherProps = computed(() => {
      if (props.useSelection) return { rowSelection };
      return {};
    });

    // 表格分页数据
    const tablePagination = computed(() => {
      if (props.pagination) return pageable.value;
      return false;
    });

    const tableColumnsData = ref<TableProps['columns']>(props.columns);

    // 获取表格配置项
    const tableColumns = computed(() => {
      let tableColumnsList: TableProps['columns'] = tableColumnsData.value
        .filter((s)=>!s.hidden)
        .map((item) => ({
          ...item,
          ellipsis: true,
          key: item.dataIndex,
        }))

      if (shouldSort.value) {
        const columns = {
          dataIndex: '__sort__',
          title: '-',
          width: 60,
        };
        tableColumnsList.unshift(columns);
      }

      if (!props.merge) return tableColumnsList;

      tableColumnsList.forEach((v) => {
        v.customCell = (scope: any) => {
          const row = scope.customCell
            ? scope.customCell[v.dataIndex] ?? { rowSpan: 1 }
            : { rowSpan: 1 };
          const col = scope.customCellCol
            ? scope.customCellCol[v.dataIndex] ?? { colSpan: 1 }
            : { colSpan: 1 };
          return {
            ...col,
            ...row,
          };
        };
      });
      return tableColumnsList;
    });

    const mergeColKeys = computed(() => {
      let mergeRow = props.mergeRow;

      if (shouldSort.value) {
        return [];
      }

      return mergeRow.map((b) =>
        tableColumns.value
          .filter((_, i) => {
            if (b as number[]) {
              return (b as number[]).includes(i + 1);
            }
            return false;
          })
          .map((s: any) => s.dataIndex)
      );
    });

    const tableList = computed(() =>
      listAppendFn(tableData.value, props.merge, mergeColKeys.value)
    );

    const onLoadFn = () => {
      if (formRef.value) formRef.value.resetFields();
      reset();
      onLoad();
      emit('onload', totalParam.value);
    };

    const refresh = (resetPage:boolean) => {
      if(resetPage){
        search()
      }else{
        search(1);
      }
      onLoad();
      emit('onload', totalParam.value);
    };

    const change = (pagination: PaginationProps) => {
      changeTable(pagination);
      onLoad();
      emit('onload', totalParam.value);
    };

    const onSearch = () => {
      search(1);
      onLoad();
      emit('onload', totalParam.value);
    };

    onMounted(() => {
      reset();
      onLoad();
      emit('onload', totalParam.value);
    });

    watch(
      selectedRowKeys,
      () => {
        emit('changeSelectedRowKeys', selectedRowKeys.value);
      },
      { deep: true, immediate: false }
    );

    // 过滤需要搜索的配置项
    const searchColumns = computed(() =>
      props.columns.filter((item) => item.search)
    );

    // 设置搜索表单的默认值
    searchColumns.value.forEach((column) => {
      if (
        column.searchInitParam !== undefined &&
        column.searchInitParam !== null
      ) {
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        searchInitParam.value[column.dataIndex!] = column.searchInitParam;
      }
    });

    // 监听表格数据变化后初始化拖拽方法
    watch(
      () => props.tableSource,
      () => {
        updateTableData(props.tableSource);
        initSortable();
      },
      { immediate: false, deep: true }
    );

    // 监听拖拽变更的下标并将下标传递给父级
    watch(
      sortIndex,
      () => {
        emit('changeSortIndex', sortIndex.value);
      },
      { deep: true, immediate: false }
    );

    // 点击添加按钮
    const add = () => emit('add');

    // 当前是否展示拖拽按钮
    const isShowDraggle = computed(
      () => !tableData.value.filter((v:any)=>v.children).length && props.draggle
    );

    const handleResizeColumn = (w:any, col:any) => {
      col.width = w;
      tableColumnsData.value?.forEach((v) => {
        if (v.dataIndex === col.dataIndex) {
          v.width = w;
        }
      });
    };

    const hasSlot = (name:any) => !!slots[name];

    // 导出父组件可直接调用方法
    expose({ onSelectChange, refresh, setValueByKey, getsearchParam });
    return {
      isShowDraggle,
      tableColumns,
      tableList,
      tablePagination,
      tableOtherProps,
      loading,
      rowSelection,
      tableSize,
      searchColumns,
      searchShow,
      expand,
      searchParam,
      SHOW_PARENT,
      FiledName,
      shouldSort,
      mytbref,
      hasSlot,
      add,
      change,
      handleResizeColumn,
      onSearch,
      onLoadFn,
      toogleSearchShow,
      refresh,
      setTableSize,
      setShouldSort,
      t,
      showTag,
      locale
    };
  },
});

export default LgTable as typeof LgTable & {
  readonly useTable: typeof useTable;
};
</script>
